package com.zrkizzy.module.content.service.category;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zrkizzy.common.core.domain.response.OptionsVO;
import com.zrkizzy.common.core.utils.IdUtil;
import com.zrkizzy.common.core.utils.bean.BeanCopyUtil;
import com.zrkizzy.common.models.domain.blog.category.BlogCategory;
import com.zrkizzy.common.models.dto.blog.category.BlogCategoryDTO;
import com.zrkizzy.common.models.enums.system.log.OperateType;
import com.zrkizzy.common.models.query.blog.category.BlogCategoryQuery;
import com.zrkizzy.common.redis.service.IRedisService;
import com.zrkizzy.content.facade.service.category.IBlogCategoryService;
import com.zrkizzy.module.content.constant.DefaultValueConst;
import com.zrkizzy.module.content.exception.BlogErrorCode;
import com.zrkizzy.module.content.mapper.category.BlogCategoryMapper;
import com.zrkizzy.system.facade.annotation.OperationLog;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;

import static com.zrkizzy.common.redis.enums.RedisKey.OPTIONS_CATEGORY_KEY;

/**
 * <p>
 * 博客分类业务逻辑接口实现类
 * </p>
 *
 * @author zhangrongkang
 * @since 2023/9/4
 */
@Service
@Slf4j
public class BlogCategoryServiceImpl implements IBlogCategoryService {

    @Autowired
    private IdUtil idUtil;

    @Autowired
    private IRedisService redisService;

    @Autowired
    private BlogCategoryMapper categoryMapper;

    /**
     * 获取所有博客分类
     *
     * @param categoryQuery 博客分类查询对象
     * @return 博客分类分页数据
     */
    @Override
    public Page<BlogCategory> listBlogCategories(BlogCategoryQuery categoryQuery) {
        // 开启分页
        Page<BlogCategory> page = new Page<>(categoryQuery.getCurrentPage(), categoryQuery.getPageSize());
        // 查询分页
        return categoryMapper.listBlogCategories(page, categoryQuery);
    }

    /**
     * 添加或更新博客分类
     *
     * @param categoryDTO 博客分类数据接收对象
     * @return 是否添加/更新成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveBlogCategory(BlogCategoryDTO categoryDTO) {
        // 校验是否存在同名博客分类
        BlogCategory blogCategory = getBlogCategoryByName(categoryDTO.getName());
        // 清除博客分类选项缓存
        redisService.del(OPTIONS_CATEGORY_KEY.getKey());
        // 如果存在ID，判断是否添加重名
        if (null != categoryDTO.getId()) {
            // 校验是否重名
            checkForDuplicateName(categoryDTO.getId(), blogCategory);
            return updateCategory(categoryDTO);
        }
        // 如果不存在ID，判断是否存在同名分类
        checkForDuplicateName(null, blogCategory);
        // 添加博客分类
        return insertCategory(categoryDTO);
    }

    /**
     * 获取指定博客分类信息
     *
     * @param categoryId 博客分类ID
     * @return 博客分类数据返回对象
     */
    @Override
    public BlogCategory getBlogCategoryById(Long categoryId) {
        return categoryMapper.selectById(categoryId);
    }

    /**
     * 根据博客分类名称查询博客分类
     *
     * @param name 博客分类名称
     * @return 博客分类对象
     */
    @Override
    public BlogCategory getBlogCategoryByName(String name) {
        // 定义查询条件
        QueryWrapper<BlogCategory> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", name);
        // 返回查询结果
        return categoryMapper.selectOne(queryWrapper);
    }

    /**
     * 批量删除博客分类数据
     *
     * @param ids 博客分类ID
     * @return true：删除成功，false：删除失败
     */
    @Override
    public Boolean deleteBatch(List<Long> ids) {
        // 清除博客分类选项缓存
        redisService.del(OPTIONS_CATEGORY_KEY.getKey());
        // 删除数据库中数据
        return categoryMapper.deleteBatchIds(ids) == ids.size();
    }

    /**
     * 获取所有博客分类选项
     *
     * @return 分类选项集合
     */
    @Override
    public List<OptionsVO> listOptions() {
        // 博客分类Key
        String key = OPTIONS_CATEGORY_KEY.getKey();
        if (redisService.hasKey(key)) {
            return redisService.getList(key, OptionsVO.class);
        }
        // 查询设置缓存并返回
        return loadCache();
    }

    /**
     * 更新当前博客分类
     *
     * @param categoryDTO 博客分类数据接收对象
     * @return 是否更新成功
     */
    @OperationLog(type = OperateType.UPDATE)
    private Boolean updateCategory(BlogCategoryDTO categoryDTO) {
        log.info("--------------------- 执行更新操作 ---------------------");
        // 对博客分类进行更新操作并返回响应结果
        return categoryMapper.updateById(BeanCopyUtil.copy(categoryDTO, BlogCategory.class)) == 1;
    }
    
    /**
     * 添加新的博客分类
     *
     * @param categoryDTO 博客分类数据接收对象
     * @return 是否添加成功
     */
    @OperationLog(type = OperateType.ADD)
    private Boolean insertCategory(BlogCategoryDTO categoryDTO) {
        log.info("--------------------- 开始进行新增操作 ---------------------");
        // 生成博客分类ID
        Long id = idUtil.nextId();
        // 设置ID
        categoryDTO.setId(id);
        // 默认文章数量
        categoryDTO.setCount(DefaultValueConst.DEFAULT_ARTICLE_COUNT);
        // 添加博客分类数据并返回添加结果
        return categoryMapper.insert(BeanCopyUtil.copy(categoryDTO, BlogCategory.class)) == 1;
    }

    /**
     * 校验是否存在重名博客分类
     *
     * @param categoryId 博客分类ID
     * @param blogCategory 根据传来参数查询出的博客分类对象
     */
    private void checkForDuplicateName(Long categoryId, BlogCategory blogCategory) {
        // 定义校验异常
        if (blogCategory != null && (categoryId == null || !categoryId.equals(blogCategory.getId()))) {
            throw BlogErrorCode.CATEGORY_NAME_EXIST.exception();
        }
    }

    /**
     * 加载博客分类缓存
     *
     * @return 博客分类集合数据
     */
    private List<OptionsVO> loadCache() {
        // 博客分类Key
        String key = OPTIONS_CATEGORY_KEY.getKey();
        // 查询分类选项
        List<OptionsVO> categories = categoryMapper.listOptions();
        // 不为空则存储到Redis
        if (!CollectionUtils.isEmpty(categories)) {
            // 过期时间为不过期，更新时进行清空操作
            redisService.setList(key, categories);
        }
        return categories;
    }

}
